//This include is needed for the general 628 function call stuff
#include <system.h>
#include "globalopts.h"

#include "usart.h"
#include "gc_menu.h"
#include "menu.h"
#include "lcd.h"
#include "p18f1320_extra.h"

#define VERSION "0.92"		//Define Version number here

//#define SIMULATOR		DO NOT DEFINE THIS HERE!.  DEFINE IN globalopts.h!!!
#define DEBUG

#pragma CLOCK_FREQ 8000000
//#pragma DATA _CONFIG1, _LVP_OFF & _BODEN_ON & _MCLR_OFF & _WDT_ON & _PWRTE_ON & _INTRC_IO //0x3F54
#pragma DATA  _CONFIG1H, _INTIO2_OSC_1H
#pragma DATA  _CONFIG2L, _PWRT_ON_2L & _BOR_ON_2L & _BORV_27_2L
#pragma DATA  _CONFIG2H, _WDT_ON_2H & _WDTPS_32_2H // 128 msec Watch-dog
#pragma DATA  _CONFIG3H, _MCLRE_OFF_3H
#pragma DATA  _CONFIG4L, _DEBUG_OFF_4L & _LVP_OFF_4L & _STVR_ON_4L

#pragma DATA  _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L
#pragma DATA  _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
#pragma DATA  _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L
#pragma DATA  _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
#pragma DATA  _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L
#pragma DATA  _CONFIG7H, _EBTRB_OFF_7H

//We'd like to use IDLOC for the version, but the Micropro programmer
//only writes the low niblle of each byte.
#ifdef SIMULATOR
	rom char *version_str = VERSION "sim";
#else
	rom char *version_str = VERSION;
#endif

//pump control flags (flags)
#define ADREADY			0
#define TICK_1MSEC		1
#define TICK_1SEC		2
#define TICK_5SEC		3
#define TICK_1MIN		4
#define AD_HILO			5

char           flags;
char           t2_overflow0 = 0;
//char           t2_overflow1 = 0;
unsigned short t2_overflow2 = 0;

char           next_keg;
unsigned char  debug_flags  = 0;

#ifdef SIMULATOR
//char		sim_timer_adj = 0;
#endif

void show_status()
{
	ClearScreen();
	sendFromRom(5, 16);
	SetPosLine2();
	if(test_bit(debug_flags, DEBUG_AD)) {
		sendDecimalShort(keginfo[0].d.tank_weight);
		sendChar(' ');
		sendDecimalShort(keginfo[1].d.tank_weight);
		sendChar(' ');
		sendDecimalShort(keginfo[2].d.tank_weight);
	} else {
		sendChar(' ');
		sendDecimalBytePad(keginfo[0].d.pints, 2);
		sendChar(' ');
		sendChar(' ');
		sendChar(' ');
		sendDecimalBytePad(keginfo[1].d.pints, 2);
		sendChar(' ');
		sendChar(' ');
		sendChar(' ');
		sendDecimalBytePad(keginfo[2].d.pints, 2);
	}
}

void interrupt()
{
//	porta=tmp;
//	tmp^=0x04;
	if (test_bit(pir1, ADIF)) {
		set_bit(flags, ADREADY);
		clear_bit(pir1, ADIF);
	}
	if(test_bit(intcon, TMR0IF)) {
		clear_bit(t0con, TMR0ON);	//Turn off timer0
		clear_bit(intcon, TMR0IF);
		set_bit(flags, TICK_1MSEC);
	}
	if (test_bit(pir1, TMR2IF)) {
		clear_bit(pir1, TMR2IF);
		// This timer should overflow every 32.7msec
#ifdef SIMULATOR
		//We adjust the timer speed to account for gpsim running ~2x the
		//native speed
		//if(++sim_timer_adj >= 8 && (sim_timer_adj = 0 ) == 0)
#endif
		{
			// Trigger every ~1sec (31*32.7ms = ~1sec)
			if(31 == ++t2_overflow0) {
				t2_overflow0 = 0;
				set_bit(flags, TICK_1SEC);
			}

			// Trigger every ~5sec (152*32.7ms = ~5sec)
			//if(152 == ++t2_overflow1) {
			//	t2_overflow1 = 0;
			//	set_bit(flags, TICK_5SEC);
			//}

			// Count number of overflows for 1 minute (1831*32.7ms = 60 sec)
			if(1831 == ++t2_overflow2) {
				t2_overflow2=0;
				set_bit(flags, TICK_1MIN);
			}
			menu_callback();
		}
	}
	if (test_bit(intcon, RBIF)) {
		check_grey_int();
		clear_bit(intcon, RBIF);
	}
}

inline void set_supply()
{
	//This requires that flags and porta are previously initialized
	toggle_bit(flags, AD_HILO);
	porta ^= 0x88;
	tmr0l = 0;		//Reset timer 0 and turn it on
	set_bit(t0con, TMR0ON);	//This will give us 1ms for volatges to settle
}

//Start the main - this is the very first stuff the PIC will run
void main()
{
	unsigned char i;

	osccon=0x70;
	//wdtcon=0xf7; //Watchdog timeout=~2sec
	clear_wdt();
	
	porta = 0x00;	//Clear porta 1st (as per spec sheet)
	trisa = 0x77 ;	//PORTA 6:4,2:0 inputs, 7,3 outputs

	latb = 0x02;	//set all ports to '0' except for Tx pin
	trisb = 0xff;	//PORTB 7:0 inputs

	adcon0 = 0x01;	//Enable A/D module, use internal references
	adcon1 = 0xf8;	//PORTA 2:0 are analog, all others are digital
	adcon2 = AD_RIGHT_JUST | AD_20TAD | AD_16TOSC;	//left-justify, 20TAD aquisition, 16Tosc sample

	t0con = 0x42;	//timer0 disabled, 8:1 prescalar, 8bit
	t2con = 0xff;	//timer2 enabled, 16:1 prescaler, 16:1 postscaler

	rcsta = 0x80;	//Enable serial port
	txsta = 0x20;	//Enable transmitter, asynchronous 8-bit mode
	baudctl = 0x00;
	spbrg = 0x0c;	//9600 baud
	
	intcon3 = 0x00; //Disable external interrupts
	intcon2 = 0x01;	//PORTB pullup, high-priority RBI
	pie1 = 0x042;	//enable timer2, A/D interrupt
	intcon = 0x68;	//enable portb,peripheral, and tmr0 interrupts

	flags = 0;
	next_keg = 0;

	for(i = 0; i < NUM_KEGS; i++)
		compute_units_per_pint(i);
	init_menu();
	ClearScreen();

	set_bit(intcon, GIE); //enable interrupts
	set_bit(porta, 7);		//Set V- as hi.  set_supply will flip it lo
	set_supply();
	while(1)
	{
		clear_wdt();
		if(test_bit(flags, ADREADY)) {		//An A/D conversion is ready
			clear_bit(flags, ADREADY);
			compute_current_pints(next_keg, test_bit(flags, AD_HILO));
			if(++next_keg < NUM_KEGS) {
				adcon0 = (next_keg << 2) | 0x03;	//Start a new conversion on the next keg
			} else {
				set_supply();
			}
		}
		menu_loop();
		if(test_bit(flags, TICK_1MSEC)) {	//1ms has passed since set_supply
			clear_bit(flags, TICK_1MSEC);
			//Voltages should have settled,  start A/D conversion
			next_keg = 0;
			adcon0   = 0x03;	//Start A/D conversion on keg1
		}
		if(test_bit(flags, TICK_1SEC)) {	//1 second has passed
			clear_bit(flags, TICK_1SEC);
			menu_update_1sec();
			if(! in_menu()) {
				show_status();
			}
		}
		//if(test_bit(flags, TICK_5SEC)) {	//5 seconds have passed
		//}
		if(test_bit(flags, TICK_1MIN)) {	//1 minute has passed
			clear_bit(flags, TICK_1MIN);
			menu_update_1min();
		}
	}
	//End Main
}

